// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.ml.impl.turboComplete

import com.intellij.codeInsight.completion.CompletionParameters
import com.intellij.codeInsight.completion.CompletionResultSet
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.openapi.util.Key
import org.jetbrains.annotations.ApiStatus

/**
 * Generates suggestions for code completion. A simplified version of
 * [com.intellij.codeInsight.completion.CompletionContributor]
 *
 * Instances of this interface are generated by [KindCollector],
 * and then executed
 */
@ApiStatus.Internal
interface SuggestionGenerator {
  /**
   * Kind of completion variants, which will be suggested by this particular generator
   */
  val kind: CompletionKind

  /**
   * Result set, to where the generated completion variants will be stored after
   * [generateCompletionVariants] has been called
   */
  val result: CompletionResultSet

  /**
   * Parameters, which the generated suggestions will be satisfying
   */
  val parameters: CompletionParameters

  /**
   * Generates completion variants, which correspond to [parameters] and puts them
   * to [result]
   */
  fun generateCompletionVariants()

  companion object {
    @JvmStatic
    val LOOKUP_ELEMENT_SUGGESTION_GENERATOR = Key<SuggestionGenerator>("SuggestionGenerator which generated the lookup element")

    @JvmStatic
    fun fromGenerator(kind: CompletionKind,
                      parameters: CompletionParameters,
                      result: CompletionResultSet,
                      generateVariants: () -> Unit): SuggestionGenerator {
      return object : SuggestionGenerator {
        override val kind = kind
        override val result = result
        override val parameters = parameters

        override fun generateCompletionVariants() {
          generateVariants()
        }
      }
    }

    @JvmStatic
    fun withApplicability(kind: CompletionKind,
                          result: CompletionResultSet,
                          parameters: CompletionParameters,
                          generator: () -> Unit,
                          isApplicable: () -> Boolean): SuggestionGenerator {
      return fromGenerator(
        kind,
        parameters,
        result
      ) { if (isApplicable()) generator() else Unit }
    }

    val LookupElement.suggestionGenerator
      get() = this.getUserData(LOOKUP_ELEMENT_SUGGESTION_GENERATOR)
  }
}
